﻿using Newtonsoft.Json;
using System;
using System.IO;
using System.Text.RegularExpressions;

namespace Sustainalytics.FileManager
{
    /// <summary>
    /// File contents.
    /// </summary>
    public class FileContents
    {
        private string _filePath;


        /// <summary>
        /// File name extracted from path.
        /// </summary>
        [JsonIgnore]
        public string PathFileName { get; private set; }

        /// <summary>
        /// File path directory.
        /// </summary>
        [JsonIgnore]
        public string PathDirectory { get; private set; }

        /// <summary>
        /// File path where the file is located.
        /// </summary>
        public string FilePath
        {
            get
            {
                return _filePath;
            }

            set
            {
                _filePath = value;

                if (string.IsNullOrEmpty(value) == false)
                {
                    // set path file name
                    this.PathFileName = GetPathFileName(this.FilePath);

                    // set path directory
                    this.PathDirectory = GetPathDirectory(this.FilePath, this.PathFileName);
                }
                else
                {
                    this.PathFileName = null;
                    this.PathDirectory = null;
                }
            }
        }

        /// <summary>
        /// File metadata.
        /// </summary>
        public FileMetadata Metadata { get; set; }

        /// <summary>
        /// File stream.
        /// </summary>
        [JsonIgnore]
        public Func<Stream> StreamAccessor { get; set; }


        /// <summary>
        /// Ctor.
        /// </summary>
        public FileContents()
        {
        }

        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="filePath"> File path. </param>
        /// <param name="metadata"> Metadata. </param>
        /// <param name="streamAccessor"> Contents. </param>
        public FileContents(string filePath, FileMetadata metadata, Func<Stream> streamAccessor)
        {
            this.FilePath = filePath;
            this.Metadata = metadata;
            this.StreamAccessor = streamAccessor;
        }


        /// <summary>
        /// Extract file name from path.
        /// </summary>
        /// <returns> Path file name. </returns>
        public static string GetPathFileName(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                throw new FileContentsFilePathNullOrEmptyException();
            }

            // match last segment separated by slash which defines the path file name.
            var match = new Regex(@"(?<fileName>[^/]+)$", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase).Match(filePath);

            if (match.Success == false)
            {
                throw new FileContentsInvalidFilePathException();
            }

            return match.Groups["fileName"].Value;
        }

        /// <summary>
        /// Get path directory.
        /// </summary>
        /// <returns> Path directory. </returns>
        public static string GetPathDirectory(string filePath, string fileName)
        {
            string pathDir = filePath.Substring(0, filePath.Length - fileName.Length);

            return pathDir;
        }

        /// <summary>
        /// Concat two paths.
        /// </summary>
        /// <param name="path1"> Path 1. </param>
        /// <param name="path2"> Path 2. </param>
        /// <returns> Concatenated path. </returns>
        public static string ConcatPaths(string path1, string path2)
        {
            if (string.IsNullOrEmpty(path1))
            {
                return path2;
            }
            else
            {
                if (string.IsNullOrEmpty(path2))
                {
                    return path1;
                }
                else
                {
                    if (path1.EndsWith("/") == false)
                        path1 += "/";

                    if (path2.StartsWith("/") == false)
                        path2 = path2.Substring(1, path2.Length - 1);

                    string path = path1 + path2;
                    return path;
                }
            }
        }

        /// <summary>
        /// Get file bytes.
        /// </summary>
        /// <returns> File bytes. </returns>
        public byte[] ReadAllBytes()
        {
            if (this.StreamAccessor == null)
                return null;

            byte[] bytes;

            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (Stream stream = this.StreamAccessor())
                {
                    stream.CopyTo(memoryStream, 100000);
                }

                memoryStream.Seek(0, SeekOrigin.Begin);

                bytes = memoryStream.ToArray();
            }

            return bytes;
        }
    }
}
